package com.xinsoft.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.constant.Const;
import com.xinsoft.common.CountBean;
import com.xinsoft.entity.dto.ScmSaleNoticeDTO;
import com.xinsoft.entity.dto.ScmSaleNoticeParam;
import com.xinsoft.entity.po.*;
import com.xinsoft.entity.vo.ScmSaleListVo;
import com.xinsoft.entity.vo.ScmSaleNoticeItemVo;
import com.xinsoft.entity.vo.ScmSaleNoticeListVo;
import com.xinsoft.entity.vo.ScmSaleNoticeVo;
import com.xinsoft.mapper.ScmSaleNoticeItemMapper;
import com.xinsoft.mapper.ScmSaleOutstockMapper;
import com.xinsoft.service.*;
import com.xinsoft.mapper.ScmSaleNoticeMapper;
import com.xinsoft.utils.TokenUtil;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ZYM
 * @description 针对表【scm_sale_notice(发货通知)】的数据库操作Service实现
 * @createDate 2023-07-18 19:23:17
 */
@Service
public class ScmSaleNoticeServiceImpl extends ServiceImpl<ScmSaleNoticeMapper, ScmSaleNotice>
        implements ScmSaleNoticeService {

    @Resource
    private ScmSaleNoticeMapper saleNoticeMapper;
    @Resource
    private ScmSaleNoticeItemMapper saleNoticeItemMapper;
    @Resource
    private ScmSaleOutstockMapper saleOutstockMapper;

    @Autowired
    private SysUserService userService;
    @Autowired
    private ScmSaleNoticeItemService saleNoticeItemService;
    @Autowired
    private ScmDocumentService documentService;
    @Autowired
    private SysFileHisService fileHisService;
    @Autowired
    private SysDocumentNumService documentNumService;
    @Autowired
    private SysMaterialService materialService;
    @Autowired
    private ScmSaleService saleService;
    @Autowired
    private ScmSaleItemService saleItemService;

    @Override
    public IPage<ScmSaleNoticeListVo> findPageListByParam(ScmSaleNoticeParam param) {
        if (param.getTabType() != null && param.getTabType() == 3) {
            Integer deptId = Objects.requireNonNull(TokenUtil.getUser()).getDeptId();
            List<SysUser> userList = userService.list(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getDeptId, deptId));
            List<Integer> userIdList = userList.stream().map(SysUser::getId).collect(Collectors.toList());
            param.setMyTeam(userIdList);
        }
        Page<ScmSaleNoticeListVo> page = new Page<>(param.getCurrentPage(), param.getPageSize());
        IPage<ScmSaleNoticeListVo> pageList = saleNoticeMapper.findPageListByParam(page, param);

        // 被引用时计算可用数量
        if (pageList.getRecords().size() > 0 && Objects.equals(param.getCiteType(), 0)) {
            List<ScmSaleNoticeListVo> voList = this.calculateAvailableQuantity(pageList.getRecords());
            List<ScmSaleNoticeListVo> collect = voList.stream().filter(obj -> obj.getPrimaryUnitCount().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
            pageList.setRecords(CollectionUtil.isNotEmpty(collect) ? collect : null);
            pageList.setTotal(CollectionUtil.isNotEmpty(collect) ? collect.size() : 0);
        }
        return pageList;
    }

    /**
     * 计算可用数量
     */
    public List<ScmSaleNoticeListVo> calculateAvailableQuantity(List<ScmSaleNoticeListVo> list) {
        if (list.size() > 0) {
            // 计算被销售出库引用的数量
            List<Integer> sourceIds = list.stream().map(ScmSaleNoticeListVo::getId).distinct().collect(Collectors.toList());
            List<CountBean> countBeanList = saleOutstockMapper.getUsedCountOfSaleOutstock(sourceIds, Const.ApproveType.FHTZ);
            Map<String, CountBean> usedCountMap = countBeanList.stream().collect(Collectors.toMap(CountBean::getId, o -> o));
            list.forEach(vo -> {
                CountBean countBean = usedCountMap.get(String.join("_", vo.getId().toString(), vo.getMaterialId().toString()));
                if (countBean != null) {
                    vo.setPrimaryUnitCount(vo.getOutstockNum().subtract(countBean.getPrimaryUnitUsedCount()));
                    vo.setAuxiliaryUnitCount(vo.getSupportOutstockNum().subtract(countBean.getAuxiliaryUnitUsedCount()));
                } else {
                    vo.setPrimaryUnitCount(vo.getOutstockNum());
                    vo.setAuxiliaryUnitCount(vo.getSupportOutstockNum());
                }
            });
        }
        return list;
    }

    public List<ScmSaleNoticeListVo> findList(List<Integer> idList, List<Integer> materialIdList) {
        ScmSaleNoticeParam param = new ScmSaleNoticeParam();
        param.setIdList(idList);
        param.setMaterialIdList(materialIdList);
        List<ScmSaleNoticeListVo> listByParam = saleNoticeMapper.findPageListByParam(param);
        return this.calculateAvailableQuantity(listByParam);
    }

    @Override
    public List<ScmSaleNoticeListVo> findListByParam(ScmSaleNoticeParam param) {
        // IPage的参数 size<0 ，临时不分页
        Page<ScmSaleNoticeListVo> page = new Page<>(param.getCurrentPage(), -1);
        IPage<ScmSaleNoticeListVo> pageListByParam = saleNoticeMapper.findPageListByParam(page, param);
        return pageListByParam.getRecords();
    }

    @Override
    public Integer tempSave(ScmSaleNoticeDTO saleNoticeDTO) {
        if (CollectionUtils.isEmpty(saleNoticeDTO.getScmSaleNoticeItemList())) {
            throw new BDException("发货通知明细不能为空");
        }
        ScmSaleNotice saleNotice = new ScmSaleNotice();
        BeanUtils.copyProperties(saleNoticeDTO, saleNotice);
        saleNotice.setApproveStatus(Const.ApproveStatus.STAGING);
        saleNotice.setDoClose(Const.CloseStatus.NOT_CLOSED);
        saleNotice.setApplyPersonId(TokenUtil.getUserId());
        saleNotice.setApplyTime(new Date());

        List<ScmSaleNoticeItem> itemList = saleNoticeDTO.getScmSaleNoticeItemList();
        List<SysFileHis> fileHisList = saleNoticeDTO.getSysFileHisList();
        this.checkNum(itemList);
        if (Objects.isNull(saleNotice.getId())) {
            // 更新计划单号
            documentNumService.incrementLastSerialByDocumentId(Const.DOCUMENT_ID.SALE_NOTICE_DOCUMENT);
            this.save(saleNotice);
        } else {
            documentService.remove(Wrappers.lambdaQuery(ScmDocument.class).eq(ScmDocument::getScmId, saleNotice.getId()));
            saleNoticeItemService.remove(Wrappers.lambdaQuery(ScmSaleNoticeItem.class).eq(ScmSaleNoticeItem::getSaleNoticeId, saleNotice.getId()));
            this.updateById(saleNotice);
        }
        // 保存发货通知明细
        itemList.forEach(item -> {
            item.setSaleNoticeId(saleNotice.getId());
            item.setSourceType(Const.ApproveType.XSDD);
        });
        saleNoticeItemService.saveBatch(itemList);
        // 保存附件
        documentService.saveDocument(fileHisList, saleNotice.getId(), Const.ApproveType.FHTZ);
        return saleNotice.getId();
    }

    /**
     * 校验数量
     *
     * @param itemList 生产领用明细
     */
    public void checkNum(List<ScmSaleNoticeItem> itemList) {
        List<String> failMsgList = new ArrayList<>();
        List<Integer> sourceIds = itemList.stream().map(ScmSaleNoticeItem::getSourceId).distinct().collect(Collectors.toList());
        List<Integer> materialIds = itemList.stream().map(ScmSaleNoticeItem::getMaterialId).distinct().collect(Collectors.toList());
        List<SysMaterial> sysMaterials = materialService.listByIds(materialIds);
        Map<Integer, String> materialMap = sysMaterials.stream().collect(Collectors.toMap(SysMaterial::getId, SysMaterial::getMaterialName));
        // 校验可执行数量
        // 关联销售订单
        List<ScmSaleListVo> list = saleService.findList(sourceIds, materialIds, 0);
        Map<String, ScmSaleListVo> voMap = list.stream().collect(Collectors.toMap(vo -> String.join("_", vo.getId().toString(), vo.getMaterialId().toString()), vo -> vo));
        itemList.forEach(item -> {
            String key = String.join("_", item.getSourceId().toString(), item.getMaterialId().toString());
            if (voMap.containsKey(key) && item.getOutstockNum().compareTo(voMap.get(key).getPrimaryUnitCount()) > 0) {
                failMsgList.add(String.format("物料[%s]批次为[%s]的源单可用数量[%s]", materialMap.get(item.getMaterialId()), item.getBatch(), voMap.get(key).getPrimaryUnitCount()));
                // failMsgList.add(String.format("物料[%s]批次为[%s]的出库数量不能大于源单可用数量", materialMap.get(item.getMaterialId()), item.getBatch()));
            }
        });
        if (CollectionUtil.isNotEmpty(failMsgList)) {
            failMsgList.add("发货数量不能大于源单可用数量");
            throw new BDException(String.join(",\n", failMsgList));
        }
    }

    @Override
    public ScmSaleNoticeVo detail(Integer id) {
        ScmSaleNoticeVo saleNoticeVo = saleNoticeMapper.getById(id);
        // 1.通知明细
        List<ScmSaleNoticeItemVo> itemVos = saleNoticeItemMapper.listBySaleNoticeId(id);
        List<Integer> sourceIds = itemVos.stream().map(ScmSaleNoticeItemVo::getSourceId).distinct().collect(Collectors.toList());
        List<Integer> materialIds = itemVos.stream().map(ScmSaleNoticeItemVo::getMaterialId).distinct().collect(Collectors.toList());
        // 当前单据已用数量
        List<CountBean> countBeanList = saleNoticeMapper.getUsedCountOfSaleNotice(sourceIds, Const.ApproveType.XSDD);
        Map<String, CountBean> countBeanMap = countBeanList.stream().collect(Collectors.toMap(CountBean::getId, o -> o));
        // 源单数量
        List<ScmSaleItem> saleItems = saleItemService.list(Wrappers.lambdaQuery(ScmSaleItem.class)
                .in(ScmSaleItem::getSaleId, sourceIds)
                .in(ScmSaleItem::getMaterialId, materialIds));
        Map<String, ScmSaleItem> saleItemMap = saleItems.stream().collect(Collectors.toMap(item -> String.join("_", item.getSaleId().toString(), item.getMaterialId().toString()), item -> item));
        itemVos.forEach(item -> {
            String key = String.join("_", item.getSourceId().toString(), item.getMaterialId().toString());
            if (countBeanMap.containsKey(key) && saleItemMap.containsKey(key)) {
                CountBean countBean = countBeanMap.get(key);
                ScmSaleItem saleItem = saleItemMap.get(key);
                item.setPrimaryUnitCount(saleItem.getSaleNum().subtract(countBean.getPrimaryUnitUsedCount()));
                item.setAuxiliaryUnitCount(item.getPrimaryUnitCount().multiply(item.getConvCoefficient()));
            }
        });
        saleNoticeVo.setScmSaleNoticeItemList(itemVos);
        // 2.附件列表
        saleNoticeVo.setSysFileHisList(documentService.getFileHisListByScmId(id, Const.ApproveType.FHTZ));
        return saleNoticeVo;
    }

    @Override
    public void del(List<Integer> ids) {
        List<ScmSaleNotice> list = this.list(Wrappers.lambdaQuery(ScmSaleNotice.class)
                .eq(ScmSaleNotice::getApproveStatus, Const.ApproveStatus.STAGING)
                .in(ScmSaleNotice::getId, ids));
        if (list.size() < ids.size()) {
            throw new BDException("操作失败，只能删除暂存的发货通知");
        }
        saleNoticeItemService.remove(Wrappers.lambdaQuery(ScmSaleNoticeItem.class).in(ScmSaleNoticeItem::getSaleNoticeId, ids));
        documentService.remove(Wrappers.lambdaQuery(ScmDocument.class).in(ScmDocument::getScmId, ids));
        this.removeByIds(ids);
    }
}




